如何优化你的 vue | 您所在的位置:网站首页 › vue-cli-service build › 如何优化你的 vue |
前言
欢迎关注同名公众号《熊的猫》,文章会同步更新! 在日常开发中,最容易让人注意的就是项目编译打包的时间,特别是在较频繁打包部署时,这个时间显得很漫长。 例如:之前接手的一个项目 "冷启动" 时编译过程花费了约 86 秒: 这能忍吗?显然不能,于是打算将其进行优化,否则太影响开发体验了,下面就是在优化过程中做的一些处理。 使用 vue-cli-service inspect 可以很方便的查看 vue-cli 内置的配置内容,在终端输入:vue inspect --mode production webpack.config.production.js,就会在项目和 src 同级目录中生成 webpack.config.production.js 文件. 要得到耗时的模块,那就需要用到一些分析工具了,例如: speed-measure-webpack-plugin webpack-bundle-analyzer speed-measure-webpack-plugin这个插件可以测量网页包构建速度,并会输出各个模块编译的时长,可以帮助我们更好的找到耗时模块。 在 vue.config.js 配置 const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); module.exports = { ..., configureWebpack: (config) => { ... config.plugins.push( new SpeedMeasurePlugin(), ); }, }; 复制代码重新启动 从下图面的输出结果中,很容易看到对应的耗时模块. 这个插件以可视化网页包输出文件的大小,并且提供了交互式可缩放的树形图. 在 vue.config.js 配置 const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); + const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; module.exports = { ..., configureWebpack: (config) => { ... config.plugins.push( new SpeedMeasurePlugin(), + new BundleAnalyzerPlugin() ); }, }; 复制代码重新启动 从下图面的输出结果中,可以很容易的观察出每个模块打包后的大小. 根据 speed-measure-webpack-plugin 输出的编译时间显示,以下几个 loader 编译时间比重较大: vue-loader ts-loader babel-loader image-webpack-loader postcss-loader 关于这一部分就可以通过 thread-loader 进行优化,因为它能将这些非常耗时的内容单独放到另一个线程中执行,但并不是针对所有的 loader 都做这个处理,因为这个处理本身也是有较大的开支。注意:仅在耗时的操作中使用 thread-loader,否则使用 thread-loader 会后可能会导致项目构建时间变得更长,因为每个 worker 都是一个独立的 node.js 进程,其开销大约为 600ms 左右,同时还会限制跨进程的数据交换等。 在回顾下前面,没有使用 thread-loader 前项目的 "冷启动" 时间约 86 秒: 只针对 babel-loader 使用 thread-loader 后项目的 "冷启动" 时间约 78 秒: PS:在对其他 loader 使用 thread-loader 发现时间更长,因此取尝试后的最优结果 webpack 中几种缓存方式: cache-loader hard-source-webpack-plugin babel-loader 的 cacheDirectory 标志以上这些缓存方式都有首次启动时的开销,即它们会让 "冷启动" 时间会更长,但是二次启动能够节省很多时间. 而 vue-cli 已经内置了 cache-loader 和 babel-loader 的 cacheDirectory 标志,其中对应的配置如下: 默认情况下的 "二次启动" 时间约为 38 秒,原因是 "冷启动" 时已经将 babel-laoder、ts-loader、vue-loader 进行了缓存:
先配置 hard-source-webpack-plugin 插件: const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; + const HardSourceWebpackPlugin = require('hard-source-webpack-plugin'); module.exports = { ..., configureWebpack: (config) => { ... config.plugins.push( // 为模块提供中间缓存,缓存路径是:node_modules/.cache/hard-source // 解决未检测到的配置更改 + new HardSourceWebpackPlugin({ root: process.cwd(), directories: [], environmentHash: { root: process.cwd(), directories: [], // 配置了files 的主要原因是解决配置更新,cache 不生效了的问题 // 配置后有包的变化,plugin 会重新构建一部分 cache files: ['package.json', 'yarn.lock'] } }), new SpeedMeasurePlugin(), new BundleAnalyzerPlugin(), ); }, }; 复制代码使用 hard-source-webpack-plugin 后的 "冷启动" 和 "二次启动" 时间如下: 在打包之后的 dist 目录下,查找对应的 console.log,结果如下: 可以发现 vue-cli 中默认的配置并没有将 js 文件中的一些 console.log 语句进行删除,因此这也是一些可以继续优化的内容. 这里可以通过 uglifyjs-webpack-plugin 或 terser-webpack-plugin 插件来删除注释和压缩 js 代码,具体配置可以直接点链接进行查阅. 对图片压缩针对一些对图片像素没有很高要求的图片资源进行压缩,这里可以通过 image-webpack-plugin 或 image-minimizer-webpack-plugin 进行图片资源的压缩,具体配置可以直接点链接进行查阅. 外部扩展 —— externals & cdnexternals 选项就是用于 防止 将某些 import 的包(package) 打包到 bundle 中,而是在运行时(runtime) 再去从外部获取这些 扩展依赖(external dependencies),具体可见 简单来说就是原本应该要被打包到 bundle 中的 js,现在通过配置 externals 选项,将它做外 bundle 之外的资源,即 cdn 资源,在代码运行时再去请求这个资源。 例如,下面就是在项目关于 externals 的配置: chainWebpack: (config) => { ... // 通过 CDN 方式引入资源 config.externals({ echarts: 'echarts', nprogress: 'NProgress', }); } 复制代码 DllPlugin 插件 —— 优化打包时间PS: webpack4或以上的版本,vue官方 和 react 官方 都已不推荐使用此插件 DllPlugin 插件负责将那些比较稳定(例如 vue/react 全家桶)的库进行打包拆分 bundles,下次在打包时就不需要重复进行打包,因此大幅度提升了构建的速度。 webpack4 版本中,已经集成 DllPlugin 插件,我们只需要进行配置即可,具体可见 创建 dll.js 文件,进行简单配置 const path = require('path'); const webpack = require('webpack'); module.exports = { entry: { vendor: ['echarts', 'element-ui', 'vue/dist/vue.esm.js', 'vue-router', 'vuex'], }, output: { path: path.join(__dirname, 'target'), filename: '[name].js', library: '[name]_[hash]', }, plugins: [ new webpack.DllPlugin({ // DllPlugin的name属性需要和libary保持一致 name: '[name]_[hash]', //指定当前目录 path: path.join(__dirname, '.', '[name]-manifest.json'), // context需要和webpack.config.js保持一致 context: __dirname, }), ], }; 复制代码 在 package.json 文件中配置 script 脚本:"dll": "webpack --config ./dll.js" 安装 webpack-cli,因为原本依赖中并没有安装过这个依赖,而运行这个脚本命令需要 webpack-cli 执行脚本命令 npm run dll,生成 vendor-manifest.json 文件,这个文件是用于让 DllReferencePlugin 能够映射到相应的依赖上resolve.alias 是用于创建 import 或 require 的别名,来确保模块引入变得更简单 例如,下面是项目中定义的一些别名: chainWebpack: (config) => { // 配置别名 config.resolve.alias .set('@build', pathResolve('../build')) // 构建目录 .set('@', pathResolve('../src')) .set('@api', pathResolve('../src/api')) .set('@utils', pathResolve('../src/utils')) .set('@views', pathResolve('../src/views')); } 复制代码resolve.extensions 指定为对应的文件后缀,保证在查找模块时的无用查找和递归等,即保证这个配置里的文件后缀要尽可能少。 module.noParse 是防止 webpack 解析那些任何与给定正则表达式相匹配的文件,忽略的文件中 不应该含有 import, require, define 的调用,或任何其他导入机制,通过忽略大型的 library 可以提高构建性能。 例如,vue-cli 中关于 module.noParse 的配置如下: 从 webpack-bundle-analyzer 反应的内容,可以发现某些 js 和 css 模块体积相对来说比较大,这个时候可以找到对应的文件梳理逻辑并进行代码优化,如封装 js 逻辑、抽离 css 样式等,即最基本的优化就是少书写重复的样式和逻辑,这样也能避免一些无效的重复编译. 最后欢迎关注同名公众号《熊的猫》,文章会同步更新! 以上就是一些基于 vue-cli(基于 webapck) 进行的一些优化,如果你之前没有进行过相应优化,那么你可以试试。 最后来看看优化前后,生产打包构建时间的变化: 对 webpack 转 vite 感兴趣的可食用:基于 webpack 项目接入 vite 你可能需要注意的点 往期文章推荐 2022 你还不会微前端吗 (下) — 揭秘微前端核心原理 2022 你还不会微前端吗 (上) — 从巨石应用到微应用 听说你很了解 Vue3 响应式? 给我实现一个前端的 Excel 导入和导出功能 前端性能优化到底该怎么做(上)— 开门见山 前端性能优化到底该怎么做(下)— 直捣黄龙 你知道前端水印功能是怎么实现的吗? |
今日新闻 |
推荐新闻 |
专题文章 |
CopyRight 2018-2019 实验室设备网 版权所有 |